package com.colabo.j2ee.web.oaf.security.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.colabo.j2ee.web.core.exception.CommonException;
import com.colabo.j2ee.web.core.exception.ServiceException;
import com.colabo.j2ee.web.core.pkgenerator.IPKGenerator;
import com.colabo.j2ee.web.core.servertime.IServerTime;
import com.colabo.j2ee.web.core.service.impl.DefaultServiceImpl;
import com.colabo.j2ee.web.core.vo.RecordObject;
import com.colabo.j2ee.web.oaf.orgnization.IPositionService;
import com.colabo.j2ee.web.oaf.orgnization.IStaffService;
import com.colabo.j2ee.web.oaf.orgnization.model.IPPositionVO;
import com.colabo.j2ee.web.oaf.orgnization.model.SCUserProfileVO;
import com.colabo.j2ee.web.oaf.security.IGrantService;
import com.colabo.j2ee.web.oaf.security.IResourceRelationService;
import com.colabo.j2ee.web.oaf.security.model.IPArcChannelVO;
import com.colabo.j2ee.web.oaf.security.model.IPArcGrantVO;

public class GrantServiceImpl extends DefaultServiceImpl implements IGrantService {
	Log log = LogFactory.getLog(GrantServiceImpl.class);

	public void batchCommit(RecordObject principal, List insertBeans, List deleteBeans) throws ServiceException {
		IPKGenerator keyGen = (IPKGenerator) getBean(IPKGenerator.BEAN_ID);
		IServerTime serverTime = (IServerTime) getBean(IServerTime.BEAN_ID);
		IPArcGrantVO grant;
		if (insertBeans != null) {
			for (Iterator it = insertBeans.iterator(); it.hasNext();) {
				grant = new IPArcGrantVO();
				grant.setGrantky(keyGen.getUUIDKey(grant));
				grant.setPrincipal(principal);
				grant.setPrincipalCode(principal.getLogicalKey());
				grant.setPrincipalType(principal.getClass().getName());
				RecordObject vo = (RecordObject) it.next();
				grant.setResource(vo);				
				grant.setResourceCode(vo.getLogicalKey());
				grant.setResourceType(vo.getClass().getName());

				if (existSameGrant(grant)) {
					continue;
				}

				grant.setDelFlag(IPArcGrantVO.DEL_FLAG_NORMAL);
				try {
					grant.setCreatedTimestamp(serverTime.getServerDateTime());
				} catch (CommonException e) {
					throw new ServiceException(e);
				}
				save_Hibernate_Object(grant);
			}
		}

		Map m = new HashMap();
		RecordObject vo;
		m.put("principalCode", principal.getLogicalKey());
		m.put("principalType", principal.getClass().getName());
		if (deleteBeans != null) {
			for (Iterator it = deleteBeans.iterator(); it.hasNext();) {
				vo = (RecordObject) it.next();
				m.put("resourceCode", vo.getLogicalKey());
				m.put("resourceType", vo.getClass().getName());
				delete_iBatis("auth.delGrants", new Object[] { m });
			}
		}
	}

	private boolean existSameGrant(IPArcGrantVO grant) throws ServiceException {
		List l = find_iBatis("auth.findSameGrant", grant);
		if (l != null && l.size() > 0) {
			return ((Integer) l.get(0)).intValue() > 0;
		}
		return false;
	}

	public List getAllGrants(int offset, int pageSize) throws ServiceException {
		return getGrants(null, null, null, null, null, null, offset, pageSize);
	}

	public int getAllGrantsCount() throws ServiceException {
		return getGrantCount(null, null, null, null, null, null);
	}

	public List getGrants(Class principalClass, RecordObject principal, Class resourceClass, RecordObject resource,
			IPArcChannelVO channel, Date date, int offset, int pageSize) throws ServiceException {
		Map params = new HashMap();
		if (principal != null) {
			params.put("principalType", principal.getClass().getName());
			params.put("principalCode", principal.getLogicalKey());
		} else if (principalClass != null) {
			params.put("principalType", principalClass.getName());
		}

		if (resource != null) {
			params.put("resourceType", resource.getClass().getName());
			params.put("resourceCode", resource.getLogicalKey());
		} else if (resourceClass != null) {
			params.put("resourceType", resourceClass.getName());
		}

		if (channel != null) {
			params.put("channelCode", channel.getChannelCode());
		}
		return find_iBatis("auth.getGrants", params, offset, pageSize);
	}

	public int getGrantCount(Class principalClass, RecordObject principal, Class resourceClass, RecordObject resource,
			IPArcChannelVO channel, Date date) throws ServiceException {
		Map params = new HashMap();
		if (principal != null) {
			params.put("principalType", principal.getClass().getName());
			params.put("principalCode", principal.getLogicalKey());
		} else if (principalClass != null) {
			params.put("principalType", principalClass.getName());
		}

		if (resource != null) {
			params.put("resourceType", resource.getClass().getName());
			params.put("resourceCode", resource.getLogicalKey());
		} else if (resourceClass != null) {
			params.put("resourceType", resourceClass.getName());
		}

		if (channel != null) {
			params.put("channelCode", channel.getChannelCode());
		}
		List l = find_iBatis("auth.getGrantCount", params);
		if (l != null && l.size() > 0) {
			return ((Integer) l.get(0)).intValue();
		}
		return 0;
	}

	public List getGrantsByPrincipal(RecordObject principal, Class resourceClass, IPArcChannelVO channel, Date date,
			int offset, int pageSize) throws ServiceException {
		if (principal == null) {
			throw new ServiceException("principal must not null");
		}
		List grants = getGrants(principal.getClass(), principal, resourceClass, null, channel, date, offset, pageSize);
		List ret = new ArrayList();
		IPArcGrantVO grant;
		Object o;
		for (Iterator it = grants.iterator(); it.hasNext();) {
			grant = (IPArcGrantVO) it.next();
			if (resourceClass == null) {
				try {
					o = findByID_Hibernate_Get(Class.forName(grant.getResourceType()), grant.getResourceCode());
					// FIXME
					// 若出现Grant记录无法与Resource对应(resource_code在对应resource表中不存在)
					// 时count方法和取出的结果数量与list中结果数量可能会不一致
					if (o != null) {
						ret.add(o);
					}
				} catch (ClassNotFoundException e) {
					log.warn(e);
					continue;
				}
			} else {				
				//IPArcGrantVO igt = (IPArcGrantVO)findByID_Hibernate_Get(resourceClass, grant.getResourceCode());				
				o = findByID_Hibernate_Get(resourceClass, grant.getResourceCode());				
				if (o != null) {					
						ret.add(o);					 
			    }				 					
			}
		}
		return ret;
	}

	public int getGrantCountByPrincipal(RecordObject principal, Class resourceClass, IPArcChannelVO channel, Date date)
			throws ServiceException {
		if (principal == null) {
			throw new ServiceException("principal must not null");
		}
		return getGrantCount(principal.getClass(), principal, resourceClass, null, channel, date);
	}

	public List getPrincipalGrantsByResource(RecordObject resource, IPArcChannelVO channel, int offset, int pageSize)
			throws ServiceException {
		if (resource == null) {
			throw new ServiceException("resource must not null");
		}
		List grants = getGrants(null, null, resource.getClass(), resource, channel, null, offset, pageSize);
		List ret = new ArrayList();
		IPArcGrantVO grant;
		Object o;
		for (Iterator it = grants.iterator(); it.hasNext();) {
			grant = (IPArcGrantVO) it.next();
			try {
				o = findByID_Hibernate_Get(Class.forName(grant.getPrincipalType()), grant.getPrincipalCode());
				if (o != null) {
					// FIXME
					// 若出现Grant记录无法与Principal对应(principal_code在对应principal表中不存在)
					// 时count方法和取出的结果数量与list中结果数量可能会不一致
					ret.add(o);
				}
			} catch (ClassNotFoundException e) {
				log.warn(e);
				continue;
			}
		}
		return ret;
	}

	public int getPrincipalGrantCountByResource(RecordObject resource, IPArcChannelVO channel) throws ServiceException {
		if (resource == null) {
			throw new ServiceException("resource must not null");
		}
		return getGrantCount(null, null, resource.getClass(), resource, channel, null);
	}

	public List getGrantsByPrincipal(RecordObject principal, Class resourceClass, IPArcChannelVO channel, Date date)
			throws ServiceException {
		return getGrantsByPrincipal(principal, resourceClass, channel, date, 0, 9999);
	}

	public void deleteGrants(Class principalType, RecordObject principal, Class resourceType, RecordObject resource,
			IPArcChannelVO channel) throws ServiceException {
		Map m = new HashMap();
		if (principalType != null) {
			m.put("principalType", principalType.getName());
		}
		if (principal != null) {
			m.put("principalCode", principal.getLogicalKey());
			m.put("principalType", principal.getClass().getName());
		}
		if (resourceType != null) {
			m.put("resourceType", resourceType.getName());
		}
		if (resource != null) {
			m.put("resourceCode", resource.getLogicalKey());
			m.put("resourceType", resource.getClass().getName());
		}
		if (channel != null) {
			m.put("channel", channel.getChannelCode());
		}
		delete_iBatis("auth.delGrants", new Object[] { m });
	}

	public List getAllGrantsByStaff(SCUserProfileVO staff, Class resourceClass, IPArcChannelVO channel, Date date,
			int offset, int pageSize) throws ServiceException {
		List principals = getAllPrincipalsByStaff(staff);				
		RecordObject principal;
		List ret = new ArrayList();
		int count;
		for (Iterator it = principals.iterator(); it.hasNext();) {
			principal = (RecordObject) it.next();
			count = getGrantCountByPrincipal(principal, resourceClass, channel, date);
			if (count > offset) {
				ret.addAll(getGrantsByPrincipal(principal, resourceClass, channel, date, offset, pageSize));
			}
			if (count >= offset + pageSize) {
				break;
			}
			offset = offset - count;
		}		
		LinkedHashMap   m = new LinkedHashMap();   
        for(int i=0;i<ret.size();i++){   
                m.put(ret.get(i),ret.get(i));
        }        
        ArrayList alist = new ArrayList(m.keySet());   
		return alist;
	}
    
	private List getAllPrincipalsByStaff(SCUserProfileVO staff) throws ServiceException {
		if (staff == null) {
			return new ArrayList(0);
		}
		ArrayList alist = new ArrayList();
		//对所有用户添加公用岗位
		IPositionService positionService = (IPositionService)getBean(IPositionService.BEAN_ID);
		List pList = positionService.getPublicPosition();
		if(pList != null){
			alist.addAll(pList);
		}
		List l = positionService.getPositionsByStaff(staff);
		if(l != null){
			alist.addAll(l);
		}
		List rl = positionService.getRolesByStaff(staff);
		if(rl != null){
			alist.addAll(rl);
		}
		return alist;
	}

	public List getAllGrantsByStaff(SCUserProfileVO staff, Class resourceClass, IPArcChannelVO channel, Date date)
			throws ServiceException {
		return getAllGrantsByStaff(staff, resourceClass, channel, date, 0, 9999);
	}

	public List getAllGrantsWithRelatedResourceByStaff(SCUserProfileVO staff, IPArcChannelVO channel, Date date)
			throws ServiceException {
		IResourceRelationService rrService = (IResourceRelationService) getBean(IResourceRelationService.BEAN_ID);
		List resources = getAllGrantsByStaff(staff, null, channel, date), 
		ret = new ArrayList();
		if(resources.size() > 0){
		   ret.addAll(resources);
		}
		RecordObject vo;
		for (Iterator it = resources.iterator(); it.hasNext();) {
			vo = (RecordObject) it.next();
			ret.addAll(rrService.getAllRelatedResources(vo));
		}
		return ret;
	}

	public int getAllGrantCountByStaff(SCUserProfileVO staff, Class resourceClass, IPArcChannelVO channel, Date date)
			throws ServiceException {
		if (staff == null) {
			return 0;
		}
		List principals = getAllPrincipalsByStaff(staff);
		int ret = 0;
		for (Iterator it = principals.iterator(); it.hasNext();) {
			ret += getGrantCountByPrincipal((RecordObject) it.next(), resourceClass, channel, date);
		}
		return ret;
	}

	public int getAllGrantedStaffCountByResource(RecordObject resource, IPArcChannelVO channel) throws ServiceException {
		// FIXME 返回值不准确, 应返回principal对应staff数量,这里只返回principal数量
		return getPrincipalGrantCountByResource(resource, channel);
	}

	public List getAllGrantedStaffsByResource(RecordObject resource, IPArcChannelVO channel, int offset, int pageSize)
			throws ServiceException {
		List l = getPrincipalGrantsByResource(resource, channel, offset, pageSize);
		Set ret = new HashSet();
		for (Iterator it = l.iterator(); it.hasNext() && ret.size() < offset + pageSize;) {
			ret.addAll(getAllStaffsByPrincipal((RecordObject) it.next()));
		}
		return new ArrayList(ret).subList(offset, pageSize > l.size() ? l.size() : pageSize);
	}

	private List getAllStaffsByPrincipal(RecordObject principal) throws ServiceException {
		if (principal == null) {
			return new ArrayList(0);
		}
		IStaffService staffService = (IStaffService)getBean(IStaffService.BEAN_ID);
		return staffService.getStaffsByPosition((IPPositionVO) principal);
	}

	public boolean isAdmin(String username) throws ServiceException {
		IPositionService positionService = (IPositionService) this.getBean(IPositionService.BEAN_ID);
		if(positionService.isHasAdminPosition(username)){
			  return  true;
	 	}						
		return false;
	}

	public List getFunctionList(String code) throws ServiceException {
		Map para = new HashMap();
		para.put("position", code);
		return find_iBatis("auth.getFunctionList", para);
	}

	public List getMenuCodeList(String code) throws ServiceException {
		Map para = new HashMap();
		para.put("position", code);
		return find_iBatis("auth.getMenuCodeList", para);
	}

	public List getUrlList(String code) throws ServiceException {
		Map para = new HashMap();
		para.put("position", code);
		return find_iBatis("auth.getUrlList", para);
	} 		
	
}
